home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / cc03.arc / NROCMD.C < prev    next >
Text File  |  1986-03-14  |  17KB  |  646 lines

  1. /*
  2.  *      Command processor for NRO text processor
  3.  *
  4.  *      Stephen L. Browning
  5.  *      5723 North Parker Avenue
  6.  *      Indianapolis, Indiana 46220
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include "nro.h"
  11. #include "nroxtrn.h"
  12.  
  13. char *skipbl();
  14. char *skipwd();
  15.  
  16. comand(p)
  17. char *p;
  18. {
  19.         int ct, val;
  20.         int spval;
  21.         int index;
  22.         char argtyp;
  23.         char name[MAXLINE];
  24.         char macexp[MXMLEN];
  25.  
  26.         ct = comtyp(p,macexp);
  27.         if (ct == UNKNOWN) {
  28.                 printf("*** nro: unrecognized command %s\n",p);
  29.                 return;
  30.         }
  31.         expesc(p,name);
  32.         val = getval(p,&argtyp);
  33.         switch (ct) {
  34.         case BO: /* bold face */
  35.                 set(&dc.boval,val,argtyp,1,0,HUGE);
  36.                 dc.cuval = dc.ulval = 0;
  37.                 break;
  38.         case BP: /* begin page */
  39.                 if(pg.lineno > 0) space(HUGE);
  40.                 set(&pg.curpag,val,argtyp,pg.curpag+1,-HUGE,HUGE);
  41.                 pg.newpag = pg.curpag;
  42.                 break;
  43.         case BR: /* break */
  44.                 brk();
  45.                 break;
  46.         case BS: /* backspaces in output */
  47.                 set(&dc.bsflg,val,argtyp,1,0,1);
  48.                 break;
  49.         case CC: /* command character */
  50.                 if (argtyp == '\r' || argtyp == '\n') dc.cmdchr = '.';
  51.                 else dc.cmdchr = argtyp;
  52.                 break;
  53.         case CE: /* center */
  54.                 brk();
  55.                 set(&dc.ceval,val,argtyp,1,0,HUGE);
  56.                 break;
  57.         case CU: /* continuous underline */
  58.                 set(&dc.cuval,val,argtyp,1,0,HUGE);
  59.                 dc.ulval = dc.boval = 0;
  60.                 break;
  61.         case DE: /* define macro */
  62.                 defmac(p,sofile[dc.flevel]);
  63.                 break;
  64.         case EF: /* even footer */
  65.                 gettl(p,pg.efoot,&pg.eflim[0]);
  66.                 break;
  67.         case EH: /* even header */
  68.                 gettl(p,pg.ehead,&pg.ehlim[0]);
  69.                 break;
  70.         case EN: /* end macro definition */
  71.                 puts("***nro: missing .de command\n");
  72.                 break;
  73.         case FI: /* fill */
  74.                 brk();
  75.                 dc.fill = YES;
  76.                 break;
  77.         case FO: /* footer */
  78.                 gettl(p,pg.efoot,&pg.eflim[0]);
  79.                 gettl(p,pg.ofoot,&pg.oflim[0]);
  80.                 break;
  81.         case HE: /* header */
  82.                 gettl(p,pg.ehead,&pg.ehlim[0]);
  83.                 gettl(p,pg.ohead,&pg.ohlim[0]);
  84.                 break;
  85.         case IN: /* indenting */
  86.                 set(&dc.inval,val,argtyp,0,0,dc.rmval-1);
  87.                 dc.tival = dc.inval;
  88.                 break;
  89.         case JU: /* justify */
  90.                 dc.juval = YES;
  91.                 break;
  92.         case LS: /* line spacing */
  93.                 set(&dc.lsval,val,argtyp,1,1,HUGE);
  94.                 break;
  95.         case M1: /* set topmost margin */
  96.                 set(&pg.m1val,val,argtyp,2,0,HUGE);
  97.                 break;
  98.         case M2: /* set second top margin */
  99.                 set(&pg.m2val,val,argtyp,2,0,HUGE);
  100.                 break;
  101.         case M3: /* set first bottom margin */
  102.                 set(&pg.m3val,val,argtyp,2,0,HUGE);
  103.                 pg.bottom = pg.plval - pg.m4val - pg.m3val;
  104.                 break;
  105.         case M4: /* set bottom-most margin */
  106.                 set(&pg.m4val,val,argtyp,2,0,HUGE);
  107.                 pg.bottom = pg.plval - pg.m4val - pg.m3val;
  108.                 break;
  109.         case MACRO: /* macro expansion */
  110.                 maceval(p,macexp);
  111.                 break;
  112.         case NE: /* need n lines */
  113.                 brk();
  114.                 if ((pg.bottom-pg.lineno+1) < (val*dc.lsval)) {
  115.                         space(HUGE);
  116.                 }
  117.                 break;
  118.         case NF: /* no fill */
  119.                 brk();
  120.                 dc.fill = NO;
  121.                 break;
  122.         case NJ: /* no justify */
  123.                 dc.juval = NO;
  124.                 break;
  125.         case NR: /* set number register */
  126.                 p = skipwd(p);
  127.                 p = skipbl(p);
  128.                 if (!isalpha(*p)) {
  129.                         puts("***nro: invalid or missing number register name\n");
  130.                 }
  131.                 else {
  132.                         index = tolower(*p) - 'a';
  133.                         p = skipwd(p);
  134.                         val = getval(p,&argtyp);
  135.                         set(&dc.nr[index],val,argtyp,0,-HUGE,HUGE);
  136.                 }
  137.                 break;
  138.         case OF: /* odd footer */
  139.                 gettl(p,pg.ofoot,&pg.oflim[0]);
  140.                 break;
  141.         case OH: /* odd header */
  142.                 gettl(p,pg.ohead,&pg.ohlim[0]);
  143.                 break;
  144.         case PC: /* page number character */
  145.                 if (argtyp == '\r' || argtyp == '\n') dc.pgchr = EOS;
  146.                 else dc.pgchr = argtyp;
  147.                 break;
  148.         case PL: /* page length */
  149.                 set(&pg.plval,val,argtyp,PAGELEN,
  150.                         pg.m1val+pg.m2val+pg.m3val+pg.m4val+1,HUGE);
  151.                 pg.bottom = pg.plval - pg.m3val - pg.m4val;
  152.                 break;
  153.         case PO: /* page offset */
  154.                 set(&pg.offset,val,argtyp,0,0,HUGE);
  155.                 break;
  156.         case RM: /* right margin */
  157.                 set(&dc.rmval,val,argtyp,PAGEWIDTH,dc.tival+1,HUGE);
  158.                 break;
  159.         case SO: /* source file */
  160.                 p = skipwd(p);
  161.                 p = skipbl(p);
  162.                 if (getwrd(p,name) == 0) break;
  163.                 if (dc.flevel+1 >= NFILES) {
  164.                         puts("***nro: .so commands nested too deeply\n");
  165.                         exit(-1);
  166.                 }
  167.                 if ((sofile[dc.flevel+1] = fopen(name,"r")) == NULL) {
  168.                         printf("***nro: unable to open %s\n",name);
  169.                         exit(-1);
  170.                 }
  171.                 ++dc.flevel;
  172.                 break;
  173.         case SP: /* space */
  174.                 set(&spval,val,argtyp,1,0,HUGE);
  175.                 space(spval);
  176.                 break;
  177.         case TI: /* temporary indent */
  178.                 brk();
  179.                 set(&dc.tival,val,argtyp,0,0,dc.rmval);
  180.                 break;
  181.         case UL: /* underline */
  182.                 set(&dc.ulval,val,argtyp,0,1,HUGE);
  183.                 dc.cuval = dc.boval = 0;
  184.                 break;
  185.         }
  186. }
  187.  
  188.  
  189.  
  190. /*
  191.  *      convert ascii character to decimal.
  192.  */
  193.  
  194. atod(c)
  195. char c;
  196. {
  197.         return(((c < '0') || (c > '9')) ? -1 : c-'0');
  198. }
  199.  
  200.  
  201.  
  202. /*
  203.  *      end current filled line
  204.  */
  205.  
  206. brk()
  207. {
  208.         if(co.outp > 0) {
  209.                 co.outbuf[co.outp] = '\r';
  210.                 co.outbuf[co.outp + 1] = '\n';
  211.                 co.outbuf[co.outp + 2] = EOS;
  212.                 put(co.outbuf);
  213.         }
  214.         co.outp = 0;
  215.         co.outw = 0;
  216.         co.outwds = 0;
  217. }
  218.  
  219.  
  220. /*
  221.  *      Collect macro definition from input stream
  222.  */
  223.  
  224. colmac(p,d,i)
  225. char *p, d[];
  226. int i;
  227. {
  228.         while (*p != EOS) {
  229.                 if (i >= MXMLEN-1) {
  230.                         d[i-1] = EOS;
  231.                         return(ERR);
  232.                 }
  233.                 d[i++] = *p++;
  234.         }
  235.         d[i] = EOS;
  236.         return(i);
  237. }
  238.  
  239.  
  240.  
  241.  
  242. /*
  243.  *      decodes nro command and returns its associated
  244.  *      value.
  245.  */
  246.  
  247. comtyp(p,m)
  248. char *p;
  249. char *m;
  250. {
  251.         char c1, c2;
  252.         char macnam[MNLEN];
  253.         char *s;
  254.  
  255.         p++;
  256.         /*
  257.         *       First check to see if the command is a macro.
  258.         *       If it is, truncate to two characters and return
  259.         *       expansion in m.  Note that upper and lower case
  260.         *       characters are handled differently for macro names,
  261.         *       but not for normal command names.
  262.         */
  263.         getwrd(p,macnam);
  264.         macnam[2] = EOS;
  265.         if ((s = getmac(macnam)) != NULL) {
  266.                 strcpy(m,s);
  267.                 return(MACRO);
  268.         }
  269.         c1 = tolower(*p++);
  270.         c2 = tolower(*p);
  271.         if (c1 == 'b' && c2 == 'o') return(BO);
  272.         if (c1 == 'b' && c2 == 'p') return(BP);
  273.         if (c1 == 'b' && c2 == 'r') return(BR);
  274.         if (c1 == 'b' && c2 == 's') return(BS);
  275.         if (c1 == 'c' && c2 == 'c') return(CC);
  276.         if (c1 == 'c' && c2 == 'e') return(CE);
  277.         if (c1 == 'c' && c2 == 'u') return(CU);
  278.         if (c1 == 'd' && c2 == 'e') return(DE);
  279.         if (c1 == 'e' && c2 == 'f') return(EF);
  280.         if (c1 == 'e' && c2 == 'h') return(EH);
  281.         if (c1 == 'e' && c2 == 'n') return(EN);
  282.         if (c1 == 'f' && c2 == 'i') return(FI);
  283.         if (c1 == 'f' && c2 == 'o') return(FO);
  284.         if (c1 == 'h' && c2 == 'e') return(HE);
  285.         if (c1 == 'i' && c2 == 'n') return(IN);
  286.         if (c1 == 'j' && c2 == 'u') return(JU);
  287.         if (c1 == 'l' && c2 == 's') return(LS);
  288.         if (c1 == 'm' && c2 == '1') return(M1);
  289.         if (c1 == 'm' && c2 == '2') return(M2);
  290.         if (c1 == 'm' && c2 == '3') return(M3);
  291.         if (c1 == 'm' && c2 == '4') return(M4);
  292.         if (c1 == 'n' && c2 == 'e') return(NE);
  293.         if (c1 == 'n' && c2 == 'f') return(NF);
  294.         if (c1 == 'n' && c2 == 'j') return(NJ);
  295.         if (c1 == 'n' && c2 == 'r') return(NR);
  296.         if (c1 == 'o' && c2 == 'f') return(OF);
  297.         if (c1 == 'o' && c2 == 'h') return(OH);
  298.         if (c1 == 'p' && c2 == 'c') return(PC);
  299.         if (c1 == 'p' && c2 == 'l') return(PL);
  300.         if (c1 == 'p' && c2 == 'o') return(PO);
  301.         if (c1 == 'r' && c2 == 'm') return(RM);
  302.         if (c1 == 's' && c2 == 'o') return(SO);
  303.         if (c1 == 's' && c2 == 'p') return(SP);
  304.         if (c1 == 't' && c2 == 'i') return(TI);
  305.         if (c1 == 'u' && c2 == 'l') return(UL);
  306.         return(UNKNOWN);
  307. }
  308.  
  309.  
  310.  
  311. /*
  312.  *      convert string to decimal.
  313.  *      processes only positive values.
  314.  */
  315.  
  316. ctod(p)
  317. char *p;
  318. {
  319.         int val, d;
  320.  
  321.         val = 0;
  322.         while(*p != EOS) {
  323.                 d = atod(*p++);
  324.                 if(d == -1) return(val);
  325.                 val = 10 * val + d;
  326.         }
  327.         return(val);
  328. }
  329.  
  330.  
  331. /*
  332.  *      Define a macro
  333.  */
  334.  
  335. defmac(p,infp)
  336. char *p;
  337. FILE *infp;
  338. {
  339.         int i;
  340.         char name[MNLEN];
  341.         char defn[MXMLEN];
  342.         char *q;
  343.  
  344.         q = skipwd(p);
  345.         q = skipbl(q);
  346.         i = getwrd(q,name);
  347.         if (!isalpha(*name)) {
  348.                 puts("***nro: missing or illegal macro definition name\n");
  349.                 exit(-1);
  350.         }
  351.         if (i > 2) name[2] = EOS;
  352.         i = 0;
  353.         while (getlin(p,infp) != EOF) {
  354.                 if (p[0] == dc.cmdchr && tolower(p[1]) == 'e' && tolower(p[2]) == 'n') {
  355.                         break;
  356.                 }
  357.                 if ((i = colmac(p,defn,i)) == ERR) {
  358.                         puts("***nro: macro definition too long\n");
  359.                         exit(-1);
  360.                 }
  361.         }
  362.         if (putmac(name,defn) == ERR) {
  363.                 puts("***nro: macro definition table full\n");
  364.                 exit(-1);
  365.         }
  366. }
  367.  
  368.  
  369. /*
  370.  *      Expand escape sequences
  371.  */
  372.  
  373. expesc(p,q)
  374. char *p;
  375. char *q;
  376. {
  377.         char *s, *t;
  378.  
  379.         s = p;
  380.         t = q;
  381.         while (*s != EOS) {
  382.                 if (*s != '@') {
  383.                         *t++ = *s++;
  384.                 }
  385.                 else if (*(s+1) == '@') {
  386.                         *t++ = *s++;
  387.                         ++s;
  388.                 }
  389.                 else if (tolower(*(s+1)) == 'n' && isalpha(*(s+2))) {
  390.                         s += 2;
  391.                         t += itoda(dc.nr[tolower(*s)-'a'],t,6) - 1;
  392.                         ++s;
  393.                 }
  394.                 else {
  395.                         *t++ = *s++;
  396.                 }
  397.         }
  398.         *t = EOS;
  399.         strcpy(p,q);
  400. }
  401.  
  402.  
  403.  
  404. /*
  405.  *      Get macro definition from table
  406.  */
  407.  
  408. char *getmac(name)
  409. char *name;
  410. {
  411.         int i;
  412.  
  413.         for (i = mac.lastp; i >= 0; --i) {
  414.                 if (!strcmp(name,mac.mnames[i])) {
  415.                         return(mac.mnames[i] + 3);
  416.                 }
  417.         }
  418.         return(NULL);
  419. }
  420.  
  421.  
  422.  
  423.  
  424. /*
  425.  *      get header or footer title
  426.  */
  427.  
  428. gettl(p,q,limit)
  429. char *p;
  430. char *q;
  431. int limit[];
  432. {
  433.         p = skipwd(p);
  434.         p = skipbl(p);
  435.         strcpy(q,p);
  436.         limit[LEFT] = dc.inval;
  437.         limit[RIGHT] = dc.rmval;
  438. }
  439.  
  440.  
  441.  
  442. /*
  443.  *      retrieves optional argument following nro command.
  444.  *      returns positive integer value with sign (if any)
  445.  *      saved in character addressed by p_argt.
  446.  */
  447.  
  448. getval(p,p_argt)
  449. char *p;
  450. char *p_argt;
  451. {
  452.         p = skipwd(p);
  453.         p = skipbl(p);
  454.         *p_argt = *p;
  455.         if((*p == '+') || (*p == '-')) ++p;
  456.         return(ctod(p));
  457. }
  458.  
  459.  
  460. /*
  461.  *      Evaluate macro expansion
  462.  */
  463.  
  464. maceval(p,m)
  465. char *p;
  466. char m[];
  467. {
  468.         int i, j;
  469.         char *argp[10];
  470.         char c;
  471.  
  472.         *p++ = EOS;             /* replace command char with EOS */
  473.         /*
  474.         *       initialize argp array to substitute command
  475.         *       string for any undefined argument
  476.         */
  477.         for (i=0; i<10; ++i) argp[i] = p;
  478.         p = skipwd(p);
  479.         *p++ = EOS;
  480.         for (i=0; i<10; ++i) {
  481.                 p = skipbl(p);
  482.                 if (*p == '\r' || *p == '\n' || *p == EOS) break;
  483.                 if (*p == '\'' || *p == '"') {
  484.                         c = *p++;
  485.                         argp[i] = p;
  486.                         while (*p != c && *p != '\r' && *p != '\n' && *p != EOS) ++p;
  487.                         *p++ = EOS;
  488.                 }
  489.                 else {
  490.                         argp[i] = p;
  491.                         p = skipwd(p);
  492.                         *p++ = EOS;
  493.                 }
  494.         }
  495.         for (i=strlen(m)-1; i>=0; --i) {
  496.                 if (i > 0 && m[i-1] == '$') {
  497.                         if (!isdigit(m[i])) {
  498.                                 putbak(m[i]);
  499.                         }
  500.                         else {
  501.                                 pbstr(argp[m[i]-'0']);
  502.                                 --i;
  503.                         }
  504.                 }
  505.                 else {
  506.                         putbak(m[i]);
  507.                 }
  508.         }
  509. }
  510.  
  511.  
  512. /*
  513.  *      Push back string into input stream
  514.  */
  515.  
  516. pbstr(p)
  517. char p[];
  518. {
  519.         int i;
  520.  
  521.         for (i=strlen(p)-1; i>=0; --i) {
  522.                 putbak(p[i]);
  523.         }
  524. }
  525.  
  526.  
  527.  
  528. /*
  529.  *      Push character back into input stream
  530.  */
  531.  
  532. putbak(c)
  533. char c;
  534. {
  535.         if (mac.ppb < &mac.pbb[0]) {
  536.                 mac.ppb = &mac.pbb[0];
  537.                 *mac.ppb = c;
  538.         }
  539.         else {
  540.                 if (mac.ppb >= &mac.pbb[MAXLINE-1]) {
  541.                         puts("***nro: push back buffer overflow\n");
  542.                         exit(-1);
  543.                 }
  544.                 *++mac.ppb = c;
  545.         }
  546. }
  547.  
  548.  
  549.  
  550.  
  551. /*
  552.  *      Put macro definition into table
  553.  */
  554.  
  555. putmac(name,p)
  556. char *name;
  557. char *p;
  558. {
  559.         if (mac.lastp >= MXMDEF) return(ERR);
  560.         if (mac.emb + strlen(name) + strlen(p) + 1 > &mac.mb[MACBUF]) {
  561.                 return(ERR);
  562.         }
  563.         ++mac.lastp;
  564.         mac.mnames[mac.lastp] = mac.emb;
  565.         strcpy(mac.emb,name);
  566.         strcpy(mac.emb + strlen(name) + 1,p);
  567.         mac.emb += strlen(name) + strlen(p) + 2;
  568.         return(OK);
  569. }
  570.  
  571.  
  572.  
  573.  
  574. /*
  575.  *      set parameter and check range
  576.  */
  577.  
  578. set(param,val,type,defval,minval,maxval)
  579. int *param;
  580. int val;
  581. char type;
  582. int defval,minval,maxval;
  583. {
  584.         switch(type) {
  585.         case '\r':
  586.         case '\n':
  587.                 *param = defval;
  588.                 break;
  589.         case '+':
  590.                 *param += val;
  591.                 break;
  592.         case '-':
  593.                 *param -= val;
  594.                 break;
  595.         default:
  596.                 *param = val;
  597.                 break;
  598.         }
  599.         *param = min(*param,maxval);
  600.         *param = max(*param,minval);
  601. }
  602.  
  603.  
  604.  
  605. /*
  606.  *      skip blanks and tabs in character buffer.
  607.  *      return number of characters skipped.
  608.  */
  609.  
  610. char *skipbl(p)
  611. char *p;
  612. {
  613.         while (*p == ' ' || *p == '\t') ++p;
  614.         return(p);
  615. }
  616.  
  617.  
  618. /*
  619.  *      skip over word and punctuation
  620.  */
  621.  
  622. char *skipwd(p)
  623. char *p;
  624. {
  625.         while (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != EOS)
  626.                 ++p;
  627.         return(p);
  628. }
  629.  
  630.  
  631.  
  632. /*
  633.  *      space vertically n lines
  634.  */
  635.  
  636. space(n)
  637. int n;
  638. {
  639.         brk();
  640.         if (pg.lineno > pg.bottom) return;
  641.         if (pg.lineno == 0) phead();
  642.         skip(min(n,pg.bottom+1-pg.lineno));
  643.         pg.lineno += n;
  644.         if (pg.lineno > pg.bottom) pfoot();
  645. }
  646. r